#ifndef LOG_COLLECTION_PRIVATE_HPP
#define LOG_COLLECTION_PRIVATE_HPP

#include <array>
#include <atomic>
#include <cstdint>
#include <fcntl.h>
#include <functional>
#include <sstream>
#include <string>
#include <sys/unistd.h>
#include <systemd/sd-bus.h>
#include <type_traits>
#include <utility>
#include <vector>
#include <condition_variable>

#include "LogCollectionUtils.hpp"

namespace LogCollector
{

static constexpr const char* SYSTEMD_SERVICE_NAME { "com.shz.LogCollectorService" };
static constexpr const char* SYSTEMD_SERVICE_PATH { "/com/shz/LogCollectorService" };
static constexpr const char* SYSTEMD_SERVICE_INTERFACE { "com.shz.LogCollectorService.Interface" };

static constexpr const char* LOCAL_HANDLER_NAME { "com.shz.LocalLoggerHandler" };
static constexpr const char* LOCAL_HANDLER_PATH { "/com/shz/LocalLoggerHandler" };
static constexpr const char* LOCAL_HANDLER_INTERFACE { "com.shz.LocalLoggerHandler.Interface" };

static constexpr const uint64_t TIME_CONVERSION_BASE { 1000ULL };

static constexpr uint64_t TIME_CONVERSION_DOUBLE {
    TIME_CONVERSION_BASE * TIME_CONVERSION_BASE
};

static constexpr int TIME_YEAR_OFFSET { 1900 };

static constexpr int TIME_MONTH_OFFSET { 1 };

//! Log's default configures
static constexpr uint16_t BUFFER_SIZE { 8192 };
static constexpr uint16_t SINGLE_BUFFER_SIZE { 256 };
static constexpr uint32_t DEFAULT_MAX_FILE_SIZE { 1024 * 1024 };
static constexpr uint8_t DEFAULT_MAX_FILE_COUNT { 5 };
static constexpr uint8_t DEFAULT_MAX_FLUSH_SIZE { 255 };
static constexpr uint16_t DEFAULT_MAX_FLUSH_TIMEOUT { 0 };
static constexpr size_t ASYNC_LOG_PROCESS_QUEUE_SIZE { 100 };

static const std::string LOG_DIRECTORY { "/var/log/shz/" };
static const std::string LOG_FILE_SUFFIX { ".log" };
static const std::string LOG_FILE_BARE_FMT { LOG_DIRECTORY + "{}" + LOG_FILE_SUFFIX };
static const std::string LOG_FILE_SUBSCRIPT_FMT { LOG_DIRECTORY + "{}_{}" + LOG_FILE_SUFFIX };

static constexpr char DEFAULT_PLACEHOLDER { ' ' };

static constexpr char PLACE_MODE_LEFT { 'L' };
static constexpr char PLACE_MODE_RIGHT { 'R' };


//! inline 全局变量, 多个文件使用同一个全局变量, 不能 inline 和 static混用
//! static 全局变量，多个文件使用各自的全局变量(副本)
// inline char sWriteBuffer[BUFFER_SIZE] { 0 };
// inline uint16_t sCurrentBufferSize { 0 };
// inline uint32_t sCurrentFileSize { 0 };

static constexpr size_t BRACE_OFFSET { 2 };

template<typename T, size_t N = 0>
class NoLockSafeQueue {

struct Cell {
    std::atomic<size_t> mSeq;
    T mData;
};

public:
    NoLockSafeQueue(std::chrono::milliseconds aTimeout) : mTimeout(aTimeout) {
        
        for (size_t i = 0; i < N; ++i) {
            mBuffer[i].mSeq.store(i, std::memory_order_relaxed);
        }
    }

    ~NoLockSafeQueue() = default;

    bool enqueue(const T& data) {
        auto pos = mEnqueuePos.load(std::memory_order_relaxed);

        while (true) {
            auto& cell = mBuffer[pos % N];
            auto seq = cell.mSeq.load(std::memory_order_acquire);
            auto diff = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos);

            if (diff == 0) {
                if (mEnqueuePos.compare_exchange_weak(pos, pos + 1)) { 
                    cell.mData = data;
                    cell.mSeq.store(pos + 1, std::memory_order_release);
                    mDequeueCondition.notify_one();
                    return true;
                }
            } else if (diff < 0) {
                //! 队列full
                std::unique_lock lock(mEnqueueMutex);
                if (mEnqueueCondition.wait_for(lock, mTimeout) == std::cv_status::timeout) {
                    return false;
                }
            } else {
                pos = mEnqueuePos.load(std::memory_order_relaxed);
            }
        }
        
    }

    bool dequeue(T& aData) {
        auto pos = mDequeuePos.load(std::memory_order_relaxed);

        while (true) {
            auto& cell = mBuffer[pos % N];
            auto seq = cell.mSeq.load(std::memory_order_acquire);
            auto diff = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos + 1);

            if (diff == 0) {
                if (mDequeuePos.compare_exchange_weak(pos, pos + 1)) {
                    aData = cell.mData;
                    cell.mSeq.store(pos + N, std::memory_order_release);
                    mEnqueueCondition.notify_one();
                    return true;
                }
            } else if (diff < 0) {
                //! 队列empty
                std::unique_lock lock(mDequeueMutex);
                if (mDequeueCondition.wait_for(lock, mTimeout) == std::cv_status::timeout) {
                    return false;
                }
            }
            pos = mDequeuePos.load(std::memory_order_relaxed);
        }
    }

private:
    std::atomic<size_t> mEnqueuePos { 0 };
    std::atomic<size_t> mDequeuePos { 0 };
    std::array<Cell, N> mBuffer;

    std::chrono::milliseconds mTimeout; 

    std::mutex mEnqueueMutex;
    std::mutex mDequeueMutex;
    std::condition_variable mEnqueueCondition;
    std::condition_variable mDequeueCondition;
};

class Logger;

struct StoreLogTask {
    ReturnStatus(*mTask)(Logger* aLogger, const std::string& msg);
    std::string mMessage;
};

struct Logger
{
    int mFd;
    sd_bus* mBus;
    sd_event* mEvent;

    char* mProcessName;
    char* mExecPath;
    bool mFromLocal;
    bool mIsWriteToJournal;
    int mLevel;

    uint32_t mMaxFileSize;
    uint8_t mMaxFileCount;
    uint8_t mMaxFlushSize;
    uint16_t mMaxFlushTimeOut;

    char mWriteBuffer[BUFFER_SIZE] { 0 };
    uint16_t mCurrentBufferSize { 0 };
    uint32_t mCurrentFileSize { 0 };

    NoLockSafeQueue<StoreLogTask,
        ASYNC_LOG_PROCESS_QUEUE_SIZE> mQueue;

    ~Logger() {
        if (mEvent) {
            sd_event_unref(mEvent);
        }

        if (mBus) {
            sd_bus_unref(mBus);
        }

        if (mFd != -1) {
            close(mFd);
        }

        if (mProcessName) {
            delete[] mProcessName;
        }

        if (mExecPath) {
            delete[] mExecPath;
        }
    }
};

struct LogConfigure
{
    std::string mProcessName;
    std::string mExecPath;
    bool mFromLocal;
    bool mIsWriteToJournal;
    int mSeverityLevel;
    uint16_t mMaxFlushTimeOut;
    uint8_t mMaxFlushSize;
    uint8_t mMaxFileCount;
    uint32_t mMaxFileSize;
};

std::string __getCurrentTimestamp();

pid_t __getSelfThreadId();

pid_t __getProcessIdByName(const std::string& aProcessName);

bool __getSelfProcessName(char* aBuffer, size_t aSize);

uint64_t __getProcessStartTime(pid_t aPid);

Logger* __createDefaultLogger(const char* aProcessName = nullptr);

ReturnStatus __initLogFile(Logger* aLogger);

std::vector<LogConfigure> __loadLogConfigureAll();

LogConfigure __loadLogConfigureOne(const char* aProcessName);

ReturnStatus __writeLogSync(Logger* aLogger, Severity::Level aLevel, pid_t aTid,
    const char* aTimeStamp, const char* aFile, int aLine, const char* aFunc, const char* aFmt, ...);

ReturnStatus __writeLogVargsSync(Logger* aLogger, Severity::Level aLevel, pid_t aTid,
    const char* aTimeStamp, const char* aFile, int aLine, const char* aFunc, const char* aFmt, va_list aArgs);

ReturnStatus __writeLogAsync(Logger* aLogger, Severity::Level aLevel, pid_t aTid,
    const char* aTimeStamp, const char* aFile, int aLine, const char* aFunc, const char* aFmt, ...);

ReturnStatus __writeLogVargsAsync(Logger* aLogger, Severity::Level aLevel, pid_t aTid,
    const char* aTimeStamp, const char* aFile, int aLine, const char* aFunc, const char* aFmt, va_list aArgs);

ReturnStatus __rotateLog(Logger* aLogger);

ReturnStatus __flushLog(Logger* aLogger, const char* aOutput, int aLen);

ReturnStatus __clearLogFile(Logger* aLogger);

ReturnStatus __writeJournalVargs(Severity::Level aLevel,
    const char* aFile, int aLine, const char* aFunc, const char* aFmt, va_list aArgs);

enum class PlaceholderMode {
    Left,
    Right,

    MaxSize
};

enum class FormatArgs : uint8_t {
    Mode,
    MaxCount,
    Placeholder,

    MaxSize
};

//! std::decay_t 作用是退化 T
//! Ex. int& -> int; int[5] -> int*; const int -> int;
template<typename T>
constexpr bool is_string_like_v = 
    std::is_same_v<std::decay_t<T>, std::string> ||
    std::is_same_v<std::decay_t<T>, std::string_view> ||
    std::is_same_v<std::decay_t<T>, const char*> ||
    std::is_same_v<std::decay_t<T>, char*>;

inline std::string& format(std::string& aFormat) {
    return aFormat;
}

std::vector<std::string> __split(const std::string& aStr, char aBreakPoint);

template<typename T>
std::string format(std::string aFormat, T&& aValue) {
    //! 1. 首先要找到 "{" 和 对应的 "}"
    //! 2. 遍历 "{" -> "}", 识别相关规则

    size_t leftPos = 0;
    size_t rightPos = leftPos;

    for (size_t pos = 0; pos < aFormat.size(); ++pos) {
        if (aFormat[pos] == '{') {
            leftPos = pos;
        }

        if (aFormat[pos] == '}') {
            rightPos = pos;
        }

        if (leftPos >= rightPos) {
            continue;
        }

        //! 处理中间的规则
        //! {L X Y} {R X Y}
        //! L: 左占位符
        //! R: 右占位符
        //! X: 最大字符位
        //! Y: 占位符, 默认位' '
        PlaceholderMode mode = PlaceholderMode::Left;
        size_t counts = std::string::npos;
        char placeholder = DEFAULT_PLACEHOLDER;
        std::vector<std::string> splited = LogCollector::__split(aFormat.substr(leftPos + 1, rightPos - leftPos - 1), placeholder);
        for (uint8_t i = static_cast<uint8_t>(FormatArgs::Mode); i < static_cast<uint8_t>(FormatArgs::MaxSize) && i < splited.size(); ++i) {
            char firstChar = splited[i].front();
            switch (static_cast<FormatArgs>(i)) {
            case FormatArgs::Mode:
                if (firstChar == PLACE_MODE_LEFT) {
                    mode = PlaceholderMode::Left;
                } else if (firstChar  == PLACE_MODE_RIGHT) {
                    mode = PlaceholderMode::Right;
                }
                break;
            case FormatArgs::MaxCount:
                counts = std::stoull(splited[i]);
                break;
            case FormatArgs::Placeholder:
                placeholder = firstChar;
                break;
            default:
                break;
            }
        }

        //! 根据规则构造替换的字符串
        std::string placeStr;
        if constexpr (is_string_like_v<T>) {
            placeStr = std::forward<T>(aValue);
        } else if (std::is_arithmetic_v<T>) {
            placeStr = std::to_string(std::forward<T>(aValue));
        } else {
            std::ostringstream oss;
            oss << std::forward<T> (aValue);
            placeStr = oss.str();
        }

        auto size = placeStr.size();
        if (counts == std::string::npos || counts == size) {
            aFormat.replace(leftPos, rightPos - leftPos + 1, placeStr);
        } else if (counts < size) {
            if (mode == PlaceholderMode::Left) {
                placeStr.erase(0, size - counts);
            } else if (mode == PlaceholderMode::Right) {
                placeStr.erase(counts);
            }
            aFormat.replace(leftPos, rightPos - leftPos + 1, placeStr);
        } else if (counts > size) {
            if (mode == PlaceholderMode::Left) {
                placeStr.insert(0, counts - size, placeholder);
            } else if (mode == PlaceholderMode::Right) {
                placeStr.insert(size, counts - size, placeholder);
            }
            aFormat.replace(leftPos, rightPos - leftPos + 1, placeStr);
        }
        
        break;
    }

    return aFormat;
}

template<typename... Ts>
std::string format(std::string aFormat, Ts&&... aArgs) {
    ((aFormat = LogCollector::format(std::move(aFormat), std::forward<Ts>(aArgs))), ...);
    return aFormat;
}

}

#endif // LOG_COLLECTION_PRIVATE_HPP